// VERSION DE PUERTA USANDO ipc::bounded_counter
#include "common.hpp"

static const char *optString = "n:p:h?";

static const struct option longOpts[] = {
	{ "help", no_argument, NULL, 'h' },
	{ "name", required_argument, NULL, 'n' },
	{ "people", required_argument, NULL, 'p' },
	{ 0,0,0,0 }
};

int main (int argc, char* const argv[]) {
	srand( time(NULL) + getpid() );

	// Objetos IPC.
	//ipc::semaphore_with_exceptions mutex( ftok(BASE_NAME,10),0 );
	//ipc::shared_memory_with_exception<sGimnasio> gim( ftok(BASE_NAME,11) );
	ipc::bounded_counter gim( ftok(BASE_NAME,11), ftok(BASE_NAME,10),0 );

	// Parametros.
	std::string nombre;
	long personas = 10;

	// Variables.
	size_t accion = '\0';
	int longIndex = 0;
	int option = 0;
	bool ayuda = false;

	// Interpretación de parametros.
	while ( (option = getopt_long(argc,argv,optString,longOpts,&longIndex) ) != EOF ) {
		switch (option) {
			case '?':
			case 'h':
			case ':':
				ayuda = true;
				break;
			case 'n':
				nombre = optarg;
				break;
			case 'p':
				personas = parse(optarg,10);
				break;
			default:
				break;
		}
	}

	if ( ayuda || nombre.empty() || personas < 0) {
		std::cerr << "Proceso para liberación del entorno de ejecución." << std::endl;
		std::cerr << "\tUso: " << argv[0] << " [-h] <-name string> <-people entero>" << std::endl;
		std::cerr << "\tParametros:" << std::endl;
		std::cerr << "\t\t-h,--help:\tMostrar este mensaje de ayuda." << std::endl;
		std::cerr << "\t\t-n,--name:\tDefinir el nombre de la puerta." << std::endl;
		std::cerr << "\t\t-p,--people:\tCantidad de personas a generar en la puerta." << std::endl;

		return (nombre.empty() ? -1 : 0);
	}

	// Proceso.
	try {
		gim.get(PERMITS);

		logger << nombre << ": Inicio." << nl;
		while (personas > 0) {
			accion = rand()%2; // Selecciono que acción realizar.

			if (accion == 0) {
				gim.inc();
				if ( gim.isUltimaOperacionOK() ) {
					logger << nombre << ": Una persona entra." << nl;
					personas--;
				}
				else
					logger << nombre << ": Una persona no pudo entrar por que el gimnasio esta lleno." << nl;
			} else {
				gim.dec();
				if ( gim.isUltimaOperacionOK() ) {
					logger << nombre << ": Una persona sale." << nl;
					personas--;
				}
			}

			usleep( rand()%1000+100 ); // Simula el paso de una persona enfrente del gimnasio.
		}

		logger << nombre << ": Quedan " << gim.getActual() << " dentro del gimnasio." << nl;
	} catch (ipc::exception& e) {
		logger << nombre << ": " << e.what() << "." << nl;
		exit(-1);
	}

	logger << nombre << ": Fin." << nl;
	return 0;
}

